package com.szcinda.call.service;

import com.szcinda.call.*;
import com.szcinda.call.phone.CallbackData;
import com.szcinda.call.phone.PhoneCall;
import com.szcinda.call.repository.*;
import com.szcinda.call.sms.SendSms;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.regex.Pattern;

@Service
@Transactional
public class TicketDetailsServiceImpl implements TicketDetailsService {


    @Value("${call.exception.code}")
    private String exceptionCodeStr;

    @Value("${manual.code}")
    private String manualCode;

    private final TicketDetailsRepository ticketDetailsRepository;
    private final SnowFlakeFactory2 snowFlakeFactory2;
    private final SmsSendRepository smsSendRepository;
    private final ExceptionContext exceptionContext;
    private final SiteUserRepository siteUserRepository;

    private final static ConcurrentLinkedQueue<PhoneCallSendData> callQueue1 = new ConcurrentLinkedQueue<>();
    private final static ConcurrentLinkedQueue<PhoneCallSendData> callQueue2 = new ConcurrentLinkedQueue<>();
    private final static ConcurrentLinkedQueue<PhoneCallSendData> callQueue3 = new ConcurrentLinkedQueue<>();

    public TicketDetailsServiceImpl(TicketDetailsRepository ticketDetailsRepository, SmsSendRepository smsSendRepository,
                                    ExceptionContext exceptionContext, SiteUserRepository siteUserRepository) {
        this.ticketDetailsRepository = ticketDetailsRepository;
        this.smsSendRepository = smsSendRepository;
        this.exceptionContext = exceptionContext;
        this.siteUserRepository = siteUserRepository;
        this.snowFlakeFactory2 = SnowFlakeFactory2.getInstance();
    }

    @Override
    public String create(TicketDetailsCreateDto createDto) {
        TicketDetails details = new TicketDetails();
        BeanUtils.copyProperties(createDto, details);
        details.setTicketId(snowFlakeFactory2.nextId("TN"));
        if (details.getBaseCallNumber() == null) {
            details.setBaseCallNumber("");
        }
        if ("前台组".equals(details.getInputGroup()) && details.getBaseCallNumber().length() > 0) {
            // 需要加入打电话队列
            PhoneCallSendData sendData = new PhoneCallSendData(details.getTicketId(), details.getBaseCallNumber(), null);
            callQueue1.add(sendData);
        }
        ticketDetailsRepository.save(details);
        // 减点数
        SiteUser siteUser = siteUserRepository.findByUserName(createDto.getSystemUserName());
        siteUser.setCount(siteUser.getCount() - 1);
        siteUserRepository.save(siteUser);
        return details.getTicketId();
    }

    @Override
    public void updatePhoneCallDateTime(String ticketId, String createTime, String answerTime) {
        TicketDetails details = ticketDetailsRepository.getOne(ticketId);
        Date d = new Date(Long.parseLong(createTime));
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String status = Long.parseLong(answerTime) == 0 ? "未接通" : "已接通";
        details.setRobotStatus("处理中");
        if (details.getCallOneTime() == null) {
            details.setCallOneTime(sf.format(d));
            details.setCallbackStatus1(status);
        } else if (details.getCallTwoTime() == null) {
            details.setCallTwoTime(sf.format(d));
            details.setCallbackStatus2(status);
        } else {
            details.setCallThreeTime(sf.format(d));
            details.setCallbackStatus3(status);
            // 如果第三次还没有打通，则发送消息
            if ("未接通".equals(status)) {
                if (!Pattern.matches("^1[3-9]\\d{9}$", details.getBaseCallNumber())) {
                    SendSms.send(details.getBaseCallNumber(), details.getTrackingNumber());
                }
                details.setSmsStatus("已发送");
            }
        }
        ticketDetailsRepository.save(details);
    }

    @Override
    public void updatePhoneCallDateTime(CallbackData data) {
        TicketDetails details = ticketDetailsRepository.getOne(data.getData());
        Date d = new Date(Long.parseLong(data.getSubject().getCreateTime()));
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String status;
        Date answerTime = null;
        details.setRobotStatus("处理中");
        if (Long.parseLong(data.getSubject().getAnswerTime()) == 0) {
            status = "未接通";
        } else {
            answerTime = new Date(Long.parseLong(data.getSubject().getAnswerTime()));
            status = "已接通";
        }
        if (details.getCallOneTime() == null) {
            details.setCallOneTime(sf.format(d));
            if (answerTime != null) {
                details.setOneAnswerTime(sf.format(answerTime));
            }
            details.setOneIvrTime(data.getSubject().getIvrTime());
            details.setCallbackStatus1(status);
        } else if (details.getCallTwoTime() == null) {
            details.setCallTwoTime(sf.format(d));
            if (answerTime != null) {
                details.setTwoAnswerTime(sf.format(answerTime));
            }
            details.setTwoIvrTime(data.getSubject().getIvrTime());
            details.setCallbackStatus2(status);
        } else {
            details.setCallThreeTime(sf.format(d));
            if (answerTime != null) {
                details.setThreeAnswerTime(sf.format(answerTime));
            }
            details.setThreeIvrTime(data.getSubject().getIvrTime());
            details.setCallbackStatus3(status);
            // 如果第三次还没有打通，则发送消息
            if ("未接通".equals(status)) {
                if (!Pattern.matches("^1[3-9]\\d{9}$", details.getBaseCallNumber())) {
                    SendSms.send(details.getBaseCallNumber(), details.getTrackingNumber());
                }
                details.setSmsStatus("已发送");
                try {
                    SmsSend smsSend = new SmsSend();
                    smsSend.setId(snowFlakeFactory2.nextId("SM"));
                    smsSend.setContent("【鹏启物流】亲您好！我是百世快递的， 打您电话未接听，您查询的单号：" + details.getTrackingNumber() + "，您反馈的问题我这边已通知处理了， 建议您这边再耐心等待，给您这边带来不便非常抱歉！百世快递祝您生活愉快！");
                    smsSend.setCount(102);
                    smsSend.setPhone(details.getBaseCallNumber());
                    smsSend.setSendTime(LocalDateTime.now());
                    smsSend.setReceiveTime(LocalDateTime.now().plusMinutes(2));
                    smsSendRepository.save(smsSend);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        ticketDetailsRepository.save(details);
    }

    @Override
    public void finish(String ticketId) {
        TicketDetails details = ticketDetailsRepository.getOne(ticketId);
        details.setRobotStatus("已完成");
        details.setException("FALSE");
        ticketDetailsRepository.save(details);
    }

    @Override
    public List<QianTaiData> findQianTaiData(SearchQianTaiDataParams params) {
        Assert.hasText(params.getUserName(), "查询参数[userName]不能为空");
        Assert.hasText(params.getSite(), "查询参数[site]不能为空");
        Specification<TicketDetails> specification = ((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            Predicate userName = criteriaBuilder.equal(root.get("userName").as(String.class), params.getUserName().trim());
            predicates.add(userName);
            Predicate site = criteriaBuilder.equal(root.get("site").as(String.class), params.getSite().trim());
            predicates.add(site);
            Predicate inputGroup = criteriaBuilder.equal(root.get("inputGroup").as(String.class), "前台组");
            predicates.add(inputGroup);
            Predicate equalRobotStatus = criteriaBuilder.equal(root.get("robotStatus").as(String.class), "处理中");
            predicates.add(equalRobotStatus);
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        });
        List<TicketDetails> ticketDetails = ticketDetailsRepository.findAll(specification);
        List<QianTaiData> qianTaiDataList = new ArrayList<>();
        if (ticketDetails.size() > 0) {
            ticketDetails.forEach(ticketDetails1 -> {
                if ("已接通".equals(ticketDetails1.getCallbackStatus1()) || "已接通".equals(ticketDetails1.getCallbackStatus2()) ||
                        "已接通".equals(ticketDetails1.getCallbackStatus3()) || "已发送".equals(ticketDetails1.getSmsStatus()) ||
                        "FOR_INPUT".equals(ticketDetails1.getException())) {
                    qianTaiDataList.add(new QianTaiData(ticketDetails1.getTicketId(), ticketDetails1.getTrackingNumber()));
                }
            });
        }
        return qianTaiDataList;
    }

    @Override
    public PageResult<TicketDetails> queryExceptionData(SearchExceptionDataParams params) {
        Assert.isTrue(params.getUserNames() != null && params.getUserNames().size() > 0, "用户名参数不能为空");
        Specification<TicketDetails> specification = ((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            // 组织机构ID
            Expression<String> exp = root.get("userName");
            predicates.add(exp.in(params.getUserNames()));
            Predicate exception = criteriaBuilder.equal(root.get("exception").as(String.class), "TRUE");
            predicates.add(exception);
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        });
        Sort order = Sort.by(Sort.Direction.DESC, "addDatabaseTime");
        Pageable pageable = PageRequest.of(params.getPage() - 1, params.getPageSize(), order);
        Page<TicketDetails> details = ticketDetailsRepository.findAll(specification, pageable);
        return PageResult.of(details.getContent(), params.getPage(), params.getPageSize(), details.getTotalElements());
    }

    @Override
    public PageResult<TicketDetails> query(TicketQueryParams params) {
        Specification<TicketDetails> specification = ((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            Assert.hasText(params.getUserName(), "查询参数[userName]不能为空");
            Predicate userName = criteriaBuilder.equal(root.get("userName").as(String.class), params.getUserName().trim());
            predicates.add(userName);
            if (!StringUtils.isEmpty(params.getSite())) {
                Predicate site = criteriaBuilder.equal(root.get("site").as(String.class), params.getSite().trim());
                predicates.add(site);
            }
            if (!StringUtils.isEmpty(params.getInputGroup())) {
                Predicate inputGroup = criteriaBuilder.equal(root.get("inputGroup").as(String.class), params.getInputGroup().trim());
                predicates.add(inputGroup);
            }
            if (!StringUtils.isEmpty(params.getTrackingNumber())) {
                Predicate likeTrackingNumber = criteriaBuilder.like(root.get("trackingNumber").as(String.class), params.getTrackingNumber().trim() + "%");
                predicates.add(likeTrackingNumber);
            }
            if (!StringUtils.isEmpty(params.getProblemType())) {
                Predicate problemType = criteriaBuilder.equal(root.get("problemType").as(String.class), params.getProblemType().trim());
                predicates.add(problemType);
            }
            if (!StringUtils.isEmpty(params.getSmsStatus())) {
                Predicate smsStatus = criteriaBuilder.equal(root.get("smsStatus").as(String.class), params.getSmsStatus().trim());
                predicates.add(smsStatus);
            }
            if (!StringUtils.isEmpty(params.getRobotStatus())) {
                Predicate robotStatus = criteriaBuilder.equal(root.get("robotStatus").as(String.class), params.getRobotStatus().trim());
                predicates.add(robotStatus);
            }
            if (!StringUtils.isEmpty(params.getArtificialStatus())) {
                Predicate artificialStatus = criteriaBuilder.equal(root.get("artificialStatus").as(String.class), params.getArtificialStatus().trim());
                predicates.add(artificialStatus);
            }
            if (!StringUtils.isEmpty(params.getProblemInfoType())) {
                Predicate problemInfoType = criteriaBuilder.equal(root.get("problemInfoType").as(String.class), params.getProblemInfoType().trim());
                predicates.add(problemInfoType);
            }
            if (!StringUtils.isEmpty(params.getException())) {
                Predicate exception = criteriaBuilder.equal(root.get("exception").as(String.class), params.getException().toUpperCase());
                predicates.add(exception);
            }
            if (params.getBaseCallTimeStart() != null) {
                Predicate start = criteriaBuilder.greaterThanOrEqualTo(root.get("baseCallTime"), params.getBaseCallTimeStart().atStartOfDay());
                predicates.add(start);
            }
            if (params.getBaseCallTimeEnd() != null) {
                Predicate createTimeEnd = criteriaBuilder.lessThanOrEqualTo(root.get("baseCallTime"), params.getBaseCallTimeEnd().plusDays(1).atStartOfDay());
                predicates.add(createTimeEnd);
            }
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        });
        Sort order = Sort.by(Sort.Direction.DESC, "addDatabaseTime");
        Pageable pageable = PageRequest.of(params.getPage() - 1, params.getPageSize(), order);
        Page<TicketDetails> details = ticketDetailsRepository.findAll(specification, pageable);
        return PageResult.of(details.getContent(), params.getPage(), params.getPageSize(), details.getTotalElements());
    }

    @Override
    public PageResult<SmsData> query(SmsQueryDto params) {
        Specification<SmsSend> specification = ((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (!StringUtils.isEmpty(params.getPhone())) {
                Predicate site = criteriaBuilder.equal(root.get("phone").as(String.class), params.getPhone().trim());
                predicates.add(site);
            }
            if (params.getSendTimeStart() != null) {
                Predicate start = criteriaBuilder.greaterThanOrEqualTo(root.get("sendTime"), params.getSendTimeStart().atStartOfDay());
                predicates.add(start);
            }
            if (params.getSendTimeEnd() != null) {
                Predicate createTimeEnd = criteriaBuilder.lessThanOrEqualTo(root.get("sendTime"), params.getSendTimeEnd().plusDays(1).atStartOfDay());
                predicates.add(createTimeEnd);
            }
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        });
        Sort order = Sort.by(Sort.Direction.DESC, "sendTime");
        Pageable pageable = PageRequest.of(params.getPage() - 1, params.getPageSize(), order);
        Page<SmsSend> details = smsSendRepository.findAll(specification, pageable);
        List<SmsData> smsDataList = new ArrayList<>();
        details.forEach(detail -> {
            SmsData smsData = new SmsData();
            BeanUtils.copyProperties(detail, smsData);
            if (!Pattern.matches("^1[3-9]\\d{9}$", smsData.getPhone())) {
                smsData.setStatus("提交失败");
            }
            smsDataList.add(smsData);
        });
        return PageResult.of(smsDataList, params.getPage(), params.getPageSize(), details.getTotalElements());
    }

    @Override
    public void artificial(List<String> ticketIds) {
        ticketIds.forEach(id -> {
            TicketDetails ticketDetails = ticketDetailsRepository.findFirstByTicketId(id);
            ticketDetails.setArtificialStatus("已跟进");
            ticketDetailsRepository.save(ticketDetails);
        });
    }

    @Override
    public void reCall(String userName, String site, String trackingNumber) {
        TicketDetails ticketDetail = ticketDetailsRepository.findFirstByUserNameAndSiteAndTrackingNumberAndInputGroupAndRobotStatusNotLike(userName, site, trackingNumber, "前台组", "已完成");
        Assert.isTrue(ticketDetail != null, "根据参数没有找到符合条件[前台组、状态不是已完成]的运单记录");
        String lastPhoneCall = ticketDetail.getCallOneTime() != null ? ticketDetail.getCallOneTime() :
                ticketDetail.getCallTwoTime() != null ? ticketDetail.getCallTwoTime() :
                        ticketDetail.getCallThreeTime();
        PhoneCallSendData sendData = new PhoneCallSendData(ticketDetail.getTicketId(), ticketDetail.getBaseCallNumber(), lastPhoneCall);
        if (ticketDetail.getCallOneTime() == null) {
            callQueue1.add(sendData);
        } else if (ticketDetail.getCallTwoTime() == null) {
            callQueue2.add(sendData);
        } else if (ticketDetail.getCallThreeTime() == null) {
            callQueue3.add(sendData);
        }
    }

    @Override
    public List<BillData> billQuery(BillQueryParams params) {
        String[] strStatus = new String[1];
        Specification<TicketDetails> specification = ((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            Assert.hasText(params.getUserName(), "查询参数[userName]不能为空");
            Predicate userName = criteriaBuilder.equal(root.get("userName").as(String.class), params.getUserName().trim());
            predicates.add(userName);
            if (!StringUtils.isEmpty(params.getSite())) {
                Predicate site = criteriaBuilder.equal(root.get("site").as(String.class), params.getSite().trim());
                predicates.add(site);
            }
            Predicate inputGroup = criteriaBuilder.equal(root.get("inputGroup").as(String.class), "前台组");
            predicates.add(inputGroup);
            if (!StringUtils.isEmpty(params.getPhone())) {
                Predicate likeTrackingNumber = criteriaBuilder.like(root.get("baseCallNumber").as(String.class), params.getPhone().trim());
                predicates.add(likeTrackingNumber);
            }
            if (params.getCallDate() != null) {
                Predicate start = criteriaBuilder.greaterThanOrEqualTo(root.get("baseCallTime"), params.getCallDate().atStartOfDay());
                predicates.add(start);
                Predicate createTimeEnd = criteriaBuilder.lessThanOrEqualTo(root.get("baseCallTime"), params.getCallDate().plusDays(1).atStartOfDay());
                predicates.add(createTimeEnd);
            }
            if (!StringUtils.isEmpty(params.getStatus())) {
                strStatus[0] = "通话成功".equals(params.getStatus()) ? "已接通" : "未接通";
                Predicate status = criteriaBuilder.or(criteriaBuilder.equal(root.get("callbackStatus1").as(String.class), strStatus[0]),
                        criteriaBuilder.equal(root.get("callbackStatus2").as(String.class), strStatus[0]),
                        criteriaBuilder.equal(root.get("callbackStatus3").as(String.class), strStatus[0]));
                predicates.add(status);
            }
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        });
        Sort order = Sort.by(Sort.Direction.DESC, "addDatabaseTime");
        Pageable pageable = PageRequest.of(params.getPage() - 1, 50, order);
        Page<TicketDetails> details = ticketDetailsRepository.findAll(specification, pageable);
        List<BillData> billDataList = new ArrayList<>();
        details.getContent().forEach(det -> {
            String callbackStatus1 = det.getCallbackStatus1();
            String callOneTime = det.getCallOneTime();
            int oneIvrTime = det.getOneIvrTime();
            BillData billData = new BillData();
            billData.setLocation(det.getPhoneLocation());
            billData.setPhone(det.getBaseCallNumber());
            billData.setCallLength(secondToTime(oneIvrTime));
            if (!callbackStatus1.equals("未拨打")) {
                if (StringUtils.isEmpty(strStatus[0])) {
                    billData.setStatus(callbackStatus1.equals("已接通") ? "通话成功" : "通话失败");
                    billData.setCallTime(callOneTime.replaceAll("-", "/"));
                    billDataList.add(billData);
                } else if (callbackStatus1.equals(strStatus[0])) {
                    billData.setStatus(callbackStatus1.equals("已接通") ? "通话成功" : "通话失败");
                    billData.setCallTime(callOneTime.replaceAll("-", "/"));
                    billDataList.add(billData);
                }
            }
            String callbackStatus2 = det.getCallbackStatus2();
            String callTwoTime = det.getCallTwoTime();
            int twoIvrTime = det.getTwoIvrTime();
            BillData billData2 = new BillData();
            billData2.setLocation(det.getPhoneLocation());
            billData2.setPhone(det.getBaseCallNumber());
            billData2.setCallLength(secondToTime(twoIvrTime));
            if (!callbackStatus2.equals("未拨打")) {
                if (StringUtils.isEmpty(strStatus[0])) {
                    billData2.setStatus(callbackStatus2.equals("已接通") ? "通话成功" : "通话失败");
                    billData2.setCallTime(callTwoTime.replaceAll("-", "/"));
                    billDataList.add(billData2);
                } else if (callbackStatus2.equals(strStatus[0])) {
                    billData2.setStatus(callbackStatus2.equals("已接通") ? "通话成功" : "通话失败");
                    billData2.setCallTime(callTwoTime.replaceAll("-", "/"));
                    billDataList.add(billData2);
                }
            }
            String callbackStatus3 = det.getCallbackStatus3();
            String callThreeTime = det.getCallThreeTime();
            int threeIvrTime = det.getThreeIvrTime();
            BillData billData3 = new BillData();
            billData3.setLocation(det.getPhoneLocation());
            billData3.setPhone(det.getBaseCallNumber());
            billData3.setCallLength(secondToTime(threeIvrTime));
            if (!callbackStatus3.equals("未拨打")) {
                if (StringUtils.isEmpty(strStatus[0])) {
                    billData3.setStatus(callbackStatus3.equals("已接通") ? "通话成功" : "通话失败");
                    billData3.setCallTime(callThreeTime.replaceAll("-", "/"));
                    billDataList.add(billData3);
                } else if (callbackStatus3.equals(strStatus[0])) {
                    billData3.setStatus(callbackStatus3.equals("已接通") ? "通话成功" : "通话失败");
                    billData3.setCallTime(callThreeTime.replaceAll("-", "/"));
                    billDataList.add(billData3);
                }
            }
        });
        return billDataList;
    }

    @Override
    public void changeException(List<String> ticketIds) {
        ticketIds.forEach(id -> {
            TicketDetails ticketDetails = ticketDetailsRepository.findFirstByTicketId(id);
            Assert.isTrue("TRUE".equals(ticketDetails.getException()), "状态必须为异常的订单才能操作");
            ticketDetails.setException("FOR_INPUT"); // 等待机器人取出此条记录，做录入备注操作
            ticketDetails.setArtificialStatus("已跟进"); // 人工跟进
            ticketDetailsRepository.save(ticketDetails);
        });
    }


    private static String secondToTime(int second) {
        second = second % 86400;//剩余秒数
        long hours = second / 3600;//转换小时数
        String hStr = hours < 10 ? "0" + hours : String.valueOf(hours);
        second = second % 3600;//剩余秒数
        long minutes = second / 60;//转换分钟
        String minStr = minutes < 10 ? "0" + hours : String.valueOf(minutes);
        second = second % 60;//剩余秒数
        String secondStr = second < 10 ? "0" + hours : String.valueOf(second);
        return hStr + ":" + minStr + ":" + secondStr;
    }

    public static void main(String[] args) {
        System.out.println(secondToTime(70));
    }


    @Scheduled(fixedRate = 60000)
    public void run(){
        // 第一次拨打逻辑
        PhoneCallSendData sendData = callQueue1.poll();
        if (sendData != null) {
            String lastPhoneCall = sendData.getLastPhoneCall();
            if (lastPhoneCall == null) {
                // 直接打电话，并加入第2次拨打队列
                CallbackData result = PhoneCall.call(sendData.getPhone(), sendData.getTicketId());
                if (result != null && result.getResult() != null && 0 == result.getResult().getCode()) {
                    // 更新拨打时间
                    sendData.setLastPhoneCall(String.valueOf(new Date().getTime()));
                    // 加入第2次拨打队列
                    callQueue2.add(sendData);
                } else if (result != null && result.getResult() != null && 0 != result.getResult().getCode()) {
                    // 拨打失败的情况,并且在允许重试的错误代码内
                    int callCount = sendData.getCallCount();
                    int code = result.getResult().getCode();
                    boolean flag = exceptionCodeStr.contains(String.valueOf(code));
                    if (callCount < 3 && flag) {
                        // 重新加入呼叫，3次机会
                        sendData.setCallCount(callCount + 1);
                        callQueue2.add(sendData);
                    } else {
                        TicketDetails record = ticketDetailsRepository.findFirstByTicketId(sendData.getTicketId());
                        // 判断是否是异常单
                        if (manualCode.contains(String.valueOf(code)) || result.getResult().getDescription().contains("号码超频")) {
                            record.setException("TRUE");
                            // 加队列
                            exceptionContext.putMessage(new ExceptionDto(record.getUserName(), "[" + sendData.getPhone() + "]" + result.getResult().getDescription()));
                        }
                        record.setRemark((record.getRemark() == null ? "" : record.getRemark()) + ";" + result.getResult().getDescription());
                        record.setCallOneTime(sendData.getLastPhoneCall());
                        ticketDetailsRepository.save(record);
                    }
                }
            } else {
                // 判断时间是否在10分钟之后
                Date lastPhoneCallDate = new Date(Long.parseLong(lastPhoneCall));
                long min = (new Date().getTime() - lastPhoneCallDate.getTime()) / (1000 * 60);
                if (min >= 10 && min < 15) {
                    CallbackData result = PhoneCall.call(sendData.getPhone(), sendData.getTicketId());
                    if (result != null && result.getResult() != null && 0 == result.getResult().getCode()) {
                        // 更新拨打时间
                        sendData.setLastPhoneCall(String.valueOf(new Date().getTime()));
                        // 加入第2次拨打队列
                        callQueue2.add(sendData);
                    } else if (result != null && result.getResult() != null && 0 != result.getResult().getCode()) {
                        // 拨打失败的情况,并且在允许重试的错误代码内
                        int callCount = sendData.getCallCount();
                        int code = result.getResult().getCode();
                        boolean flag = exceptionCodeStr.contains(String.valueOf(code));
                        if (callCount < 3 && flag) {
                            // 重新加入呼叫，3次机会
                            sendData.setCallCount(callCount + 1);
                            callQueue1.add(sendData);
                        } else {
                            TicketDetails record = ticketDetailsRepository.findFirstByTicketId(sendData.getTicketId());
                            // 判断是否是异常单
                            if (manualCode.contains(String.valueOf(code)) || result.getResult().getDescription().contains("号码超频")) {
                                record.setException("TRUE");
                                // 加队列
                                exceptionContext.putMessage(new ExceptionDto(record.getUserName(), "[" + sendData.getPhone() + "]" + result.getResult().getDescription()));
                            }
                            record.setRemark((record.getRemark() == null ? "" : record.getRemark()) + ";" + result.getResult().getDescription());
                            record.setCallOneTime(sendData.getLastPhoneCall());
                            ticketDetailsRepository.save(record);
                        }
                    }
                } else if (min < 10) {
                    // 放回原来队列
                    callQueue1.add(sendData);
                }
            }
        }
        // 第二次拨打逻辑
        sendData = callQueue2.poll();
        if (sendData != null) {
            String lastPhoneCall = sendData.getLastPhoneCall();
            if (lastPhoneCall == null) {
                // 直接打电话，并加入第3次拨打队列
                CallbackData result = PhoneCall.call(sendData.getPhone(), sendData.getTicketId());
                if (result != null && result.getResult() != null && 0 == result.getResult().getCode()) {
                    // 更新拨打时间
                    sendData.setLastPhoneCall(String.valueOf(new Date().getTime()));
                    // 加入第3次拨打队列
                    callQueue3.add(sendData);
                } else if (result != null && result.getResult() != null && 0 != result.getResult().getCode()) {
                    // 拨打失败的情况,并且在允许重试的错误代码内
                    int callCount = sendData.getCallCount();
                    int code = result.getResult().getCode();
                    boolean flag = exceptionCodeStr.contains(String.valueOf(code));
                    if (callCount < 3 && flag) {
                        // 重新加入呼叫，3次机会
                        sendData.setCallCount(callCount + 1);
                        callQueue2.add(sendData);
                    } else {
                        TicketDetails record = ticketDetailsRepository.findFirstByTicketId(sendData.getTicketId());
                        // 判断是否是异常单
                        if (manualCode.contains(String.valueOf(code)) || result.getResult().getDescription().contains("号码超频")) {
                            record.setException("TRUE");
                            // 加队列
                            exceptionContext.putMessage(new ExceptionDto(record.getUserName(), "[" + sendData.getPhone() + "]" + result.getResult().getDescription()));
                        }
                        record.setRemark((record.getRemark() == null ? "" : record.getRemark()) + ";" + result.getResult().getDescription());
                        record.setCallTwoTime(sendData.getLastPhoneCall());
                        ticketDetailsRepository.save(record);
                    }
                }
            } else {
                // 判断时间是否在10分钟之后
                Date lastPhoneCallDate = new Date(Long.parseLong(lastPhoneCall));
                long min = (new Date().getTime() - lastPhoneCallDate.getTime()) / (1000 * 60);
                if (min >= 10 && min < 15) {
                    // 打之前检查一下
                    TicketDetails record = ticketDetailsRepository.findFirstByTicketId(sendData.getTicketId());
                    if ("未接通".equals(record.getCallbackStatus1())) {
                        CallbackData result = PhoneCall.call(sendData.getPhone(), sendData.getTicketId());
                        if (result != null && result.getResult() != null && 0 == result.getResult().getCode()) {
                            // 更新拨打时间
                            sendData.setLastPhoneCall(String.valueOf(new Date().getTime()));
                            // 加入第3次拨打队列
                            callQueue3.add(sendData);
                        } else if (result != null && result.getResult() != null && 0 != result.getResult().getCode()) {
                            // 拨打失败的情况,并且在允许重试的错误代码内
                            int callCount = sendData.getCallCount();
                            int code = result.getResult().getCode();
                            boolean flag = exceptionCodeStr.contains(String.valueOf(code));
                            if (callCount < 3 && flag) {
                                // 重新加入呼叫，3次机会
                                sendData.setCallCount(callCount + 1);
                                callQueue2.add(sendData);
                            } else {
                                // 判断是否是异常单
                                if (manualCode.contains(String.valueOf(code)) || result.getResult().getDescription().contains("号码超频")) {
                                    record.setException("TRUE");
                                    // 加队列
                                    exceptionContext.putMessage(new ExceptionDto(record.getUserName(), "[" + sendData.getPhone() + "]" + result.getResult().getDescription()));
                                }
                                record.setRemark((record.getRemark() == null ? "" : record.getRemark()) + ";" + result.getResult().getDescription());
                                record.setCallTwoTime(sendData.getLastPhoneCall());
                                ticketDetailsRepository.save(record);
                            }
                        }
                    }
                } else if (min < 10) {
                    // 放回原来队列
                    callQueue2.add(sendData);
                }
            }
        }
        // 第三次拨打逻辑
        sendData = callQueue3.poll();
        if (sendData != null) {
            String lastPhoneCall = sendData.getLastPhoneCall();
            if (lastPhoneCall == null) {
                // 直接打电话
                CallbackData result = PhoneCall.call(sendData.getPhone(), sendData.getTicketId());
                if (result != null && result.getResult() != null && 0 != result.getResult().getCode()) {
                    // 拨打失败的情况,并且在允许重试的错误代码内
                    int callCount = sendData.getCallCount();
                    int code = result.getResult().getCode();
                    boolean flag = exceptionCodeStr.contains(String.valueOf(code));
                    if (callCount < 3 && flag) {
                        // 重新加入呼叫，3次机会
                        sendData.setCallCount(callCount + 1);
                        callQueue3.add(sendData);
                    } else {
                        TicketDetails record = ticketDetailsRepository.findFirstByTicketId(sendData.getTicketId());
                        // 判断是否是异常单
                        if (manualCode.contains(String.valueOf(code)) || result.getResult().getDescription().contains("号码超频")) {
                            record.setException("TRUE");
                            // 加队列
                            exceptionContext.putMessage(new ExceptionDto(record.getUserName(), "[" + sendData.getPhone() + "]" + result.getResult().getDescription()));
                        }
                        record.setRemark((record.getRemark() == null ? "" : record.getRemark()) + ";" + result.getResult().getDescription());
                        record.setCallThreeTime(sendData.getLastPhoneCall());
                        ticketDetailsRepository.save(record);
                    }
                }
            } else {
                // 判断时间是否在10分钟之后
                Date lastPhoneCallDate = new Date(Long.parseLong(lastPhoneCall));
                long min = (new Date().getTime() - lastPhoneCallDate.getTime()) / (1000 * 60);
                if (min >= 10 && min < 15) {
                    // 打之前检查一下
                    TicketDetails record = ticketDetailsRepository.findFirstByTicketId(sendData.getTicketId());
                    if ("未接通".equals(record.getCallbackStatus1()) && "未接通".equals(record.getCallbackStatus2())) {
                        CallbackData result = PhoneCall.call(sendData.getPhone(), sendData.getTicketId());
                        if (result != null && result.getResult() != null && 0 != result.getResult().getCode()) {
                            // 拨打失败的情况,并且在允许重试的错误代码内
                            int callCount = sendData.getCallCount();
                            int code = result.getResult().getCode();
                            boolean flag = exceptionCodeStr.contains(String.valueOf(code));
                            if (callCount < 3 && flag) {
                                // 重新加入呼叫，3次机会
                                sendData.setCallCount(callCount + 1);
                                callQueue3.add(sendData);
                            } else {
                                // 判断是否是异常单
                                if (manualCode.contains(String.valueOf(code)) || result.getResult().getDescription().contains("号码超频")) {
                                    record.setException("TRUE");
                                    // 加队列
                                    exceptionContext.putMessage(new ExceptionDto(record.getUserName(), "[" + sendData.getPhone() + "]" + result.getResult().getDescription()));
                                }
                                record.setRemark((record.getRemark() == null ? "" : record.getRemark()) + ";" + result.getResult().getDescription());
                                record.setCallThreeTime(sendData.getLastPhoneCall());
                                ticketDetailsRepository.save(record);
                            }
                        }
                    }
                } else if (min < 10) {
                    // 放回原来队列
                    callQueue3.add(sendData);
                }
            }
        }
    }


    @PostConstruct
    public void call() {
        // 先把之前没有外呼的都加到队列
        LocalDateTime now = ExceptionContext.getNowTime();
        Specification<TicketDetails> specification = ((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            Predicate equalInputGroup = criteriaBuilder.equal(root.get("inputGroup").as(String.class), "前台组");
            predicates.add(equalInputGroup);
            Predicate equalRobotStatus = criteriaBuilder.equal(root.get("robotStatus").as(String.class), "未处理");
            predicates.add(equalRobotStatus);
            Predicate start = criteriaBuilder.greaterThanOrEqualTo(root.get("addDatabaseTime"), now.minusMinutes(60));
            predicates.add(start);
            Predicate end = criteriaBuilder.lessThanOrEqualTo(root.get("addDatabaseTime"), now);
            predicates.add(end);
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        });
        List<TicketDetails> ticketDetails = ticketDetailsRepository.findAll(specification);
        if (ticketDetails.size() > 0) {
            ticketDetails.forEach(ticketDetail -> {
                String lastPhoneCall = ticketDetail.getCallOneTime() != null ? ticketDetail.getCallOneTime() :
                        ticketDetail.getCallTwoTime() != null ? ticketDetail.getCallTwoTime() :
                                ticketDetail.getCallThreeTime();
                PhoneCallSendData sendData = new PhoneCallSendData(ticketDetail.getTicketId(), ticketDetail.getBaseCallNumber(), lastPhoneCall);
                if (ticketDetail.getCallOneTime() == null) {
                    callQueue1.add(sendData);
                } else if (ticketDetail.getCallTwoTime() == null) {
                    callQueue2.add(sendData);
                } else if (ticketDetail.getCallThreeTime() == null) {
                    callQueue3.add(sendData);
                }
            });
        }
    }
}
